package cn.toolck.minitomcat.classLoader;

import cn.toolck.minitomcat.util.StaticResourceUtil;

import java.io.File;
import java.io.IOException;

/**
 * @ClassName MyClassLoader
 * @Description 自定义的类加载器，方便每一个context容器都用自己的类加载器
 * @Author Toolck Rin
 * @Date 2021/3/17 23:30
 * @Version 1.0
 **/
public class MyClassLoader extends ClassLoader {
    private String path;

    public MyClassLoader(String path) {
        this.path = path + "/";
    }

    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        Class<?> aClass = findClass(name);
        if (aClass == null) {
            aClass =  super.loadClass(name);
        }
        return aClass;
    }

    @Override
    protected Class<?> findClass(String name) {
        Class<?> clazz = null;
        String fileSub = path + name.replace(".", "/");

        String javaFilename = fileSub + ".java";
        String classFilename = fileSub + ".class";

        File javaFile = new File(javaFilename);
        File classFile = new File(classFilename);

        //当指定的Java源文件存在，且class文件不存在；或Java 源文件的修改时间比class文件的修改时间晚时，重新编译
        if (javaFile.exists() && (!classFile.exists() || javaFile.lastModified() > classFile.lastModified())) {
            //如果编译失败，或者该class文件不存在
            try {
                if (!compile(javaFilename) || !classFile.exists()) {
                    throw new ClassNotFoundException("ClassNotFoundException:" + javaFilename);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        //如果class文件存在，系统负责将该文件转换成Class对象
        if (classFile.exists()) {
            try {
                //将class文件的二进制数据读入数组
                byte[] raw = StaticResourceUtil.getBytes(classFilename);
                //调用classLoader的defineClass方法将二进制数据转换成Class对象
                clazz = defineClass(name, raw, 0, raw.length);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return clazz;
    }

    //定义编译指定JAVA文件的方法
    private boolean compile(String javaFile) throws IOException {
        System.out.println("CompileClassLoader:正在编译" + javaFile + "...");
        //调用系统的javac命令
        Process p = Runtime.getRuntime().exec("javac " + javaFile);
        try {
            //其他线程都等待这个线程完成
            p.waitFor();
        } catch (Exception e) {
            System.out.println(e);
        }
        //获取javac线程的退出值
        int ret = p.exitValue();//此 Process 对象表示的子进程的出口值。根据惯例，值 0 表示正常终止。
        //返回编译是否成功
        return ret == 0;
    }

}
